/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.entitygen;

import com.inspur.edp.caf.generator.BaseGenerator;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.field.FieldGenerator;
import com.inspur.edp.caf.generator.item.ClassGenerator;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.property.ClassPropertyGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.core.data.EntityDataCollection;
import com.inspur.edp.cef.entity.entity.dynamicProp.IDynamicPropSet;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.common.DataEqualsMethodGenerator;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.property.NestedAccessorFieldGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.enrichedassoudt.EnrichedAssoUdtGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.field.ChildFieldGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.method.copy.CopyMethodGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.AssoUdtPropGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.BaseTypePropGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.ChildPropGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.DataTypePropGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.DynamicPropSetPropertyGenerator;
import com.inspur.edp.cef.generator.entityGenerator.BaseEntityGeneratorContext;
import com.inspur.edp.cef.generator.overall.CefGeneratorContext;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

public abstract class BaseDataGenerator extends ClassGenerator {

  protected final EntityGeneratorContext ParentContext;
  protected final String NodeCode;
  protected List<MediatePropertyInfo> PropertyInfos;
  protected IGspCommonDataType Node;
  protected MediateType TargetInterfaceType;
  protected ArrayList<FieldGenerator> FieldGenerators = new ArrayList<FieldGenerator>();
  protected HashMap<String, String> ChildTypes = new HashMap<>();

  protected BaseDataGenerator(EntityGeneratorContext parContext, String nodeCode,
      MediateType targetInterfaceType) {
    super(parContext.getProjContext().getCompilationUnitInfo());
    this.NodeCode = nodeCode;
    ParentContext = parContext;
    TargetInterfaceType = targetInterfaceType;
    PropertyInfos = buildPropertyInfos();
  }

  protected BaseDataGenerator(EntityGeneratorContext parContext, IGspCommonDataType node,
      MediateType targetInterfaceType) {
    this(parContext, node.getCode(), targetInterfaceType);
    Node = node;
  }

  private List<MediatePropertyInfo> buildPropertyInfos() {
    return ((BaseEntityGeneratorContext) ParentContext.getProjContext().getCefGenContext()
            .getEntityGenContext()).getDataTypeDataGenContexts().get(NodeCode).getPropertyInfos()
            .values().stream().collect(Collectors.toList());
  }

  @Override
  protected void beforeGenerate() {
    super.beforeGenerate();
    addImport(EntityDataCollection.class.getName());
    addImport(HashMap.class.getName());
  }

  //#region ExtendChild
  @Override
  protected ArrayList<BaseGenerator> createClassExtendChildGenrators() {
    ArrayList<BaseGenerator> rez = super.createClassExtendChildGenrators();
    if (rez == null) {
      rez = new ArrayList<BaseGenerator>();
    }

    if (Node != null && Node instanceof IGspCommonObject) {
      for (IGspCommonObject childNode : ((IGspCommonObject) Node).getContainChildObjects()) {
        BaseDataGenerator childGen = createChildEntityDataClassGenerator(childNode);
        if (childGen != null) {
          rez.add(childGen);
        }
      }
    }

    for (MediatePropertyInfo propInfo : PropertyInfos) {
      SimpleDataTypeDef sdtDef =
          propInfo.getUdt() instanceof SimpleDataTypeDef ? (SimpleDataTypeDef) propInfo.getUdt()
              : null;
      if (sdtDef != null && sdtDef.getObjectType() == GspElementObjectType.Association && propInfo
          .getElement().containRefElementNotFromAssoUdt()) {
          addEnrichedAssoUdtGenerator(rez, propInfo);
      }
    }
    return rez;
  }

  protected final BaseDataGenerator createChildEntityDataClassGenerator(
      IGspCommonObject childNode) {
    BaseDataGenerator childGen = getChildsGenerator(ParentContext, childNode);
    if (childGen == null) {
      return null;
    }
    ChildTypes.put(childNode.getCode(), childGen.getName());
    return childGen;
  }

  protected void addEnrichedAssoUdtGenerator(ArrayList<BaseGenerator> list, MediatePropertyInfo propInfo) {
    CefGeneratorContext cefContext =
        ParentContext.getProjContext().getCefGenContext();
    MediateType udtType = new MediateType(null, Utils
        .getUdtType(propInfo.getElement().getUdtPkgName(), propInfo.getElement().getUdtID(),
            cefContext).getTypeFullName());
    list.add(new EnrichedAssoUdtGenerator(ParentContext, NodeCode, udtType, propInfo, getName()));
  }

  @Override
  protected ArrayList<ClassMethodGenerator> createMethodGenerators() {

    ArrayList<ClassMethodGenerator> list = super.createMethodGenerators();
    if (list == null) {
      list = new ArrayList<ClassMethodGenerator>();
    }
    list.add(getEqualsMethodGenerator());
    return list;
  }

  protected ClassMethodGenerator getEqualsMethodGenerator() {
    return new DataEqualsMethodGenerator(PropertyInfos,getName(),NodeCode,
        TargetInterfaceType.getFullName(), ParentContext);
  }

  protected abstract BaseDataGenerator getChildsGenerator(EntityGeneratorContext parContext,
      IGspCommonObject node);

  @Override
  protected final ArrayList<ClassPropertyGenerator> createPropertyGenerators() {
    ArrayList<ClassPropertyGenerator> properyGens = super.createPropertyGenerators();
    if (properyGens == null) {
      properyGens = new ArrayList<ClassPropertyGenerator>();
    }

    for (MediatePropertyInfo propertyInfo : PropertyInfos) {
      //①、propertyInfo有标签是Child类型，创建childPropertyGenerator
      if (propertyInfo.getNode() != null) {
        String privatePropName = EntityDataUtils
            .getDataChildEntityFieldName(propertyInfo.getNode().getCode());
        //首字母一样
        if(propertyInfo.getPropertyName().charAt(0) == propertyInfo.getNode().getCode().charAt(0)){
          ChildFieldGenerator privatePropGen = new ChildFieldGenerator(privatePropName,
                  propertyInfo.getReturnType());
//        if (childAttribute.objectCode().equals(propertyInfo.getPropertyName())) {
          FieldGenerators.add(privatePropGen);
//        }
        }
        ChildPropGenerator childPropGen = getChildPropGenerator(propertyInfo.getNode().getCode(),
            propertyInfo, privatePropName);
        if (childPropGen != null) {
          properyGens.add(childPropGen);
        }
      }
//      else if(propertyInfo.getExtendInfos().containsKey("AssoUdtAtrribute") && !propertyInfo.getElement().getIsUdt()){
//        List<BaseTypePropGenerator> baseTypePropGenerators = getBaseTypePropGenerators(
//                propertyInfo);
//        if (baseTypePropGenerators != null) {
//          for (BaseTypePropGenerator typeGen :baseTypePropGenerators ){
//            typeGen.setSetterOverride(false);
//            typeGen.setHasSetter(false);
//
//            properyGens.add(typeGen);
//          }
//        }
//      }
      //②、propertyInfo有标签是DataType类型，创建DataTypeProGenerator
      else if (propertyInfo.getExtendInfos().containsKey("AssoUdtAtrribute")) {
        String parentPropName = propertyInfo.getExtendInfo("AssoUdtAtrribute");
        AssoUdtPropGenerator assoUdtGen = new AssoUdtPropGenerator(ParentContext, propertyInfo, parentPropName);
        properyGens.add(assoUdtGen);
      }
      else if (propertyInfo.getElement().getIsUdt()) {
        String fieldName = NestedAccessorFieldGenerator.getFieldName(
                (IGspCommonField) propertyInfo.getElement());
        ChildFieldGenerator privatePropGen = new ChildFieldGenerator(fieldName,
                propertyInfo.getReturnType());
        FieldGenerators.add(privatePropGen);
        DataTypePropGenerator dataTypeGen = getDataTypePropGenerator(propertyInfo, fieldName);
        properyGens.add(dataTypeGen);
      }
      //③、动态属性类型
      else if (propertyInfo.getElement().getObjectType() == GspElementObjectType.DynamicProp) {
        FieldGenerators.add(
            new ChildFieldGenerator(DynamicPropSetPropertyGenerator.getFieldName(propertyInfo),
                new TypeInfo(IDynamicPropSet.class)));
        properyGens.add(getDynamicPropSetPropertyGenerator(propertyInfo));
      }
      //④、propertyInfo没有标签，创建BaseTypeProGenerator
      else {
        List<BaseTypePropGenerator> baseTypePropGenerators = getBaseTypePropGenerators(
            propertyInfo);
        if (baseTypePropGenerators != null) {
          properyGens.addAll(baseTypePropGenerators);
        }
      }
    }

//    for (Method method : TargetInterfaceType.getMethods()) {
//      AssoUdtAtrribute assoUdtAttribute = (AssoUdtAtrribute) ReflectionUtils
//          .getMethodAnnotation(method, AssoUdtAtrribute.class);
//      if (assoUdtAttribute != null) {
//        String parentPropName = ((assoUdtAttribute instanceof AssoUdtAtrribute)
//            ? assoUdtAttribute : null).parentPropName();
//        MediatePropertyInfo propertyInfo = new MediatePropertyInfo(method.getName().substring(3),
//            method);
//        AssoUdtPropGenerator assoUdtGen = new AssoUdtPropGenerator(propertyInfo, parentPropName);
//        properyGens.add(assoUdtGen);
//      }
//    }
    //if (typeof(IDynamicPropSetHost).IsAssignableFrom(TargetInterfaceType))//|| (ExtendTypes != null && ExtendTypes.Any(item => typeof(IDynamicPropSetHost).IsAssignableFrom(item))))
    //{
    //    FieldGenerators.Add(new ChildFieldGenerator(DynamicPropSetPropertyGenerator.FieldName, typeof(IDynamicPropSet)));
    //    properyGens.Add(getDynamicPropSetPropertyGenerator());
    //}
    addExtendPropertyGenerator(properyGens);

    return properyGens;
  }

  protected void addExtendPropertyGenerator(ArrayList<ClassPropertyGenerator> proGenerators) {
  }

  protected abstract ChildPropGenerator getChildPropGenerator(String childCode,
      MediatePropertyInfo propertyInfo, String privatePropName);

  protected DataTypePropGenerator getDataTypePropGenerator(MediatePropertyInfo propertyInfo,
      String fieldName) {
    return new DataTypePropGenerator(propertyInfo, fieldName);
  }

  protected List<BaseTypePropGenerator> getBaseTypePropGenerators(
      MediatePropertyInfo propertyInfo) {
    return null;
  }

  protected abstract DynamicPropSetPropertyGenerator getDynamicPropSetPropertyGenerator(
      MediatePropertyInfo propertyInfo);

  protected CopyMethodGenerator getCopyMethodGenerator() {
    return new CopyMethodGenerator(ParentContext, getName(), PropertyInfos);
  }

  //#endregion
  //#region field
  @Override
  protected ArrayList<FieldGenerator> createFieldGenerator() {
    ArrayList<FieldGenerator> fieldGenerators = super.createFieldGenerator();
    if (fieldGenerators == null) {
      fieldGenerators = FieldGenerators;
    }else{
      fieldGenerators.addAll(FieldGenerators);
    }
    return fieldGenerators;
  }
}
